
package visitor;

import java.util.ArrayList;
import syntaxtree.*;
import typecheck.*;
public class BuildTable implements BuildVisitor {
	
	  // MainClass m;
	  // ClassDeclList cl;
	public ArrayList<ClassEntry> visit(Program n) {
		ArrayList<ClassEntry> classes = new ArrayList<ClassEntry>();
		classes.add(n.m.accept(this));
		HashT simbolos = new HashT();
		for ( int i = 0; i < n.cl.size(); i++ ) {
			classes.add(n.cl.elementAt(i).accept(this));
		}
		
		//	colocando o nome das classes no hash do programa
		//	observe que todas as outras variaveis ainda estao em outros hashs
		for(ClassEntry c : classes) {
			simbolos.insert(c.getClassName(),new IdentifierType(c.getClassName()));
		}
		return classes;
	}
	
	  // Identifier i1,i2;
	  // Statement s;

	// construindo a ClassEntry da main
	public ClassEntry visit(MainClass n) {
		ClassEntry classeMain = new ClassEntry(n.i1.s,null);
		
		//construindo o MethodEntry na funcao main
		MethodEntry metodoMain = new MethodEntry("main", new IntegerType());
		HashT metodos = new HashT();
		// TODO funcao main nao retorna int obviamente
		metodos.insert("main",new IntegerType()); // deveria retornar "voidType" mas isso nao existe
		
		classeMain.addMetodos(metodoMain);
		//n.i1.accept(this);
		//classeMain.addVariavel(n.i2.s,t);
		// TODO funcao main sem variavel args pq nao tem String
		//n.i2.accept(this);
		//n.s.accept(this);
		return classeMain;
	}
	
	  // Identifier i;
	  // VarDeclList vl;
	  // MethodDeclList ml;
	//	class id (vl){ml}
	public ClassEntry visit(ClassDeclSimple n) {
		ClassEntry c = new ClassEntry(n.i.s, null);
		//n.i.accept(this);
		for ( int i = 0; i < n.vl.size(); i++ ) {
			VarEntry binding = n.vl.elementAt(i).accept(this);
			c.addSimbolo(binding.getNome(), binding.getTipo());
		}
		for ( int i = 0; i < n.ml.size(); i++ ) {
			c.addMetodos(n.ml.elementAt(i).accept(this));
		}
		return c;
	}
	
	  // Identifier i;
	  // Identifier j;
	  // VarDeclList vl;
	  // MethodDeclList ml;
	public ClassEntry visit(ClassDeclExtends n) {
		ClassEntry c = new ClassEntry(n.i.s, n.j.s);
		//n.i.accept(this);
		for ( int i = 0; i < n.vl.size(); i++ ) {
			VarEntry binding = n.vl.elementAt(i).accept(this);
			c.addSimbolo(binding.getNome(), binding.getTipo());
		}
		for ( int i = 0; i < n.ml.size(); i++ ) {
			MethodEntry met = (n.ml.elementAt(i).accept(this));
			c.addMetodos(met);
			c.addSimbolo(met.getNome(), met.getTipoDoRetorno());
		}	
		return c;
	}

	  // Type t;
	  // Identifier i;
	public VarEntry visit(VarDecl n) {
		Type t = n.t.accept(this);
		//n.i.accept(this);
		VarEntry v = new VarEntry(n.i.s, t);
		return v;
	}

	  // Type t;
	  // Identifier i;
	  // FormalList fl;
	  // VarDeclList vl;
	  // StatementList sl;
	  // Exp e;
	//	t i(fl) {vl; sl;}
	public MethodEntry visit(MethodDecl n) {
		Type t = n.t.accept(this);
		//n.i.accept(this);
		MethodEntry metodo = new MethodEntry(n.i.s,t);

		for ( int i = 0; i < n.fl.size(); i++ ) {
			VarEntry var = n.fl.elementAt(i).accept(this);
			metodo.addSimbolo(var.getNome(), var.getTipo());
		}
		for ( int i = 0; i < n.vl.size(); i++ ) {
			VarEntry var = n.vl.elementAt(i).accept(this);
			metodo.addSimbolo(var.getNome(), var.getTipo());
		}
		/*
			nao ha nada de util para a criacao da table de simbolos num statement
		
		for ( int i = 0; i < n.sl.size(); i++ ) {
			n.sl.elementAt(i).accept(this);
		}
		
		*/

		//	Nao ha nada importante numa expression para a tabela de simbolos.
		
		//	n.e.accept(this);
		return metodo;
	}

	  // Type t;
	  // Identifier i;
	//	int x, t i
	public VarEntry visit(Formal n) {
		Type t = n.t.accept(this);
		//n.i.accept(this);
		return new VarEntry(n.i.s, t);
	}

	public Type visit(IntArrayType n) {
		return new IntArrayType();
	}

	public Type visit(BooleanType n) {
		return new BooleanType();
	}

	public Type visit(IntegerType n) {
		return new IntegerType();
	}

	  // String s;
	public Type visit(IdentifierType n) {
		return new IdentifierType(n.s);
	}

	  // StatementList sl;
	public void visit(Block n) {
		/*
		for ( int i = 0; i < n.sl.size(); i++ ) {
			n.sl.elementAt(i).accept(this);
		}
		*/
	}

	  // Exp e;
	  // Statement s1,s2;
	public void visit(If n) {
		/*
		n.e.accept(this);
		n.s1.accept(this);
		n.s2.accept(this);
		*/
	}

	  // Exp e;
	  // Statement s;
	public void visit(While n) {
		/*
		n.e.accept(this);
		n.s.accept(this);
		*/
	}

	  // Exp e;
	public void visit(Print n) {
		
		//n.e.accept(this);
	}
	
	  // Identifier i;
	  // Exp e;
	public void visit(Assign n) {
		/*
		n.i.accept(this);
		n.e.accept(this);
		*/
	}

	  // Identifier i;
	  // Exp e1,e2;
	public void visit(ArrayAssign n) {
//		n.i.accept(this);
//		n.e1.accept(this);
//		n.e2.accept(this);
	}

	  // Exp e1,e2;
	public void visit(And n) {
//		n.e1.accept(this);
//		n.e2.accept(this);
	}

	  // Exp e1,e2;
	public void visit(LessThan n) {
//		n.e1.accept(this);
//		n.e2.accept(this);
	}

	  // Exp e1,e2;
	public void visit(Plus n) {
//		n.e1.accept(this);
//		n.e2.accept(this);
	}

	  // Exp e1,e2;
	public void visit(Minus n) {
//		n.e1.accept(this);
//		n.e2.accept(this);
	}

	  // Exp e1,e2;
	public void visit(Times n) {
//		n.e1.accept(this);
//		n.e2.accept(this);
	}

	  // Exp e1,e2;
	public void visit(ArrayLookup n) {
//		n.e1.accept(this);
//		n.e2.accept(this);
	}

	  // Exp e;
	public void visit(ArrayLength n) {
//		n.e.accept(this);
	}

	  // Exp e;
	  // Identifier i;
	  // ExpList el;
	public void visit(Call n) {
//		n.e.accept(this);
//		n.i.accept(this);
//		for ( int i = 0; i < n.el.size(); i++ ) {
//			n.el.elementAt(i).accept(this);
//		}
	}

	  // int i;
	public void visit(IntegerLiteral n) {
	}

	public void visit(True n) {
	}

	public void visit(False n) {
	}

	  // String s;
	public void visit(IdentifierExp n) {
	}

	public void visit(This n) {
	}

	  // Exp e;
	public void visit(NewArray n) {
//		n.e.accept(this);
	}

	  // Identifier i;
	public void visit(NewObject n) {
	}

	  // Exp e;
	public void visit(Not n) {
//		n.e.accept(this);
	}

	  // String s;
	public void visit(Identifier n) {
	}

}
